# -*- coding: utf-8 -*-
#  Copyright (c) 2016-2017, Zhijiang Yao, Jie Dong and Dongsheng Cao
#  All rights reserved.
#  This file is part of the PyBioMed.
#  The contents are covered by the terms of the BSD license
#  which is included in the file license.txt, found at the root
#  of the PyBioMed source tree.
"""
##############################################################################

A class used for computing different types of DNA descriptors!

You can freely use and distribute it. If you have any problem,

you could contact with us timely.

Authors: Zhijiang Yao and Dongsheng Cao.

Date: 2016.07.11

Email: gadsby@163.com and oriental-cds@163.com

##############################################################################
"""

# Core Library modules
from functools import reduce

# First party modules
from PyBioMed.PyDNA.PyDNAutil import GeneratePhycheValue, GetData


def CheckAcc(lag, k):
    """
    #################################################################
    Check ACC parameter validation.
    #################################################################
    """
    try:
        if not isinstance(lag, int) or lag <= 0:
            raise ValueError(
                "Error, parameter lag must be an int type and larger than 0."
            )
        elif not isinstance(k, int) or lag <= 0:
            raise ValueError(
                "Error, parameter k must be an int type and larger than 0."
            )
    except ValueError:
        raise


def ReadyAcc(
    input_data, k, phyche_index=None, all_property=False, extra_phyche_index=None
):
    """
    #################################################################
    Public function for get sequence_list and phyche_value.
    #################################################################
    """
    sequence_list = GetData(input_data)
    if phyche_index is None:
        phyche_index = []
    if extra_phyche_index is None:
        extra_phyche_index = {}
    phyche_value = GeneratePhycheValue(
        k, phyche_index, all_property, extra_phyche_index
    )

    return sequence_list, phyche_value


def GetDAC(input_data, **kwargs):
    """
    #################################################################
    Make DAC dictionary.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """

    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 2

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )
    from PyBioMed.PyDNA.PyDNAacutil import MakeACVector

    vec = MakeACVector(sequence_list, lag, phyche_value, k)
    dict_keys = ["DAC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


def GetDCC(input_data, **kwargs):
    """
    #################################################################
    Make DCC vector.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """
    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 2

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )
    from PyBioMed.PyDNA.PyDNAacutil import MakeCCVector

    vec = MakeCCVector(sequence_list, lag, phyche_value, k)
    dict_keys = ["DCC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


def GetDACC(input_data, **kwargs):
    """
    #################################################################
    Make DACC dictionary.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """

    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 2

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )
    from PyBioMed.PyDNA.PyDNAacutil import MakeACVector, MakeCCVector

    zipped = list(
        zip(
            MakeACVector(sequence_list, lag, phyche_value, k),
            MakeCCVector(sequence_list, lag, phyche_value, k),
        )
    )
    vec = [reduce(lambda x, y: x + y, e) for e in zipped]

    dict_keys = ["DACC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


def GetTAC(input_data, **kwargs):
    """
    #################################################################
    Make TAC dictionary.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """
    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 3

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )
    from PyBioMed.PyDNA.PyDNAacutil import MakeACVector

    vec = MakeACVector(sequence_list, lag, phyche_value, k)
    dict_keys = ["TAC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


def GetTCC(input_data, **kwargs):
    """
    #################################################################
    Make TCC dictionary.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """
    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 3

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )
    from PyBioMed.PyDNA.PyDNAacutil import MakeCCVector

    vec = MakeCCVector(sequence_list, lag, phyche_value, k)
    dict_keys = ["TCC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


def GetTACC(input_data, **kwargs):
    """
    #################################################################
    Make TACC dictionary.

    :param input_data: file object or sequence list.
    :param phyche_index: physicochemical properties list.
    :param all_property: bool, choose all physicochemical properties or not.
    :param extra_phyche_index: dict, the key is the dinucleotide (string), and its corresponding value is a list.
                               It means user-defined phyche_index.
    #################################################################
    """
    if "k" in kwargs:
        k = kwargs["k"]
    else:
        k = 3

    if "lag" in kwargs:
        lag = kwargs["lag"]
    else:
        lag = 2
    if "phyche_index" in kwargs:
        phyche_index = kwargs["phyche_index"]
    else:
        phyche_index = None
    if "all_property" in kwargs:
        all_property = kwargs["all_property"]
    else:
        all_property = False
    if "extra_phyche_index" in kwargs:
        extra_phyche_index = kwargs["extra_phyche_index"]
    else:
        extra_phyche_index = None

    input_data = [input_data]
    sequence_list, phyche_value = ReadyAcc(
        input_data, k, phyche_index, all_property, extra_phyche_index
    )

    from PyBioMed.PyDNA.PyDNAacutil import MakeACVector, MakeCCVector

    zipped = list(
        zip(
            MakeACVector(sequence_list, lag, phyche_value, k),
            MakeCCVector(sequence_list, lag, phyche_value, k),
        )
    )
    vec = [reduce(lambda x, y: x + y, e) for e in zipped]
    dict_keys = ["TCC_%s" % i for i in range(1, len(vec[0]) + 1)]
    res = dict(zip(dict_keys, vec[0]))
    return res


if __name__ == "__main__":
    extra_phyche_value = {
        "AA": [0.06, 0.5, 0.27, 1.59, 0.11, -0.11],
        "AC": [1.50, 0.50, 0.80, 0.13, 1.29, 1.04],
        "AG": [0.78, 0.36, 0.09, 0.68, -0.24, -0.62],
        "AT": [1.07, 0.22, 0.62, -1.02, 2.51, 1.17],
        "CA": [-1.38, -1.36, -0.27, -0.86, -0.62, -1.25],
        "CC": [0.06, 1.08, 0.09, 0.56, -0.82, 0.24],
        "CG": [-1.66, -1.22, -0.44, -0.82, -0.29, -1.39],
        "CT": [0.78, 0.36, 0.09, 0.68, -0.24, -0.62],
        "GA": [-0.08, 0.5, 0.27, 0.13, -0.39, 0.71],
        "GC": [-0.08, 0.22, 1.33, -0.35, 0.65, 1.59],
        "GG": [0.06, 1.08, 0.09, 0.56, -0.82, 0.24],
        "GT": [1.50, 0.50, 0.80, 0.13, 1.29, 1.04],
        "TA": [-1.23, -2.37, -0.44, -2.24, -1.51, -1.39],
        "TC": [-0.08, 0.5, 0.27, 0.13, -0.39, 0.71],
        "TG": [-1.38, -1.36, -0.27, -0.86, -0.62, -1.25],
        "TT": [0.06, 0.5, 0.27, 1.59, 0.11, -0.11],
    }
    phyche_index = [
        [
            2.26,
            3.03,
            2.03,
            3.83,
            1.78,
            1.65,
            2.00,
            2.03,
            1.93,
            2.61,
            1.65,
            3.03,
            1.20,
            1.93,
            1.78,
            2.26,
        ],
        [
            7.65,
            8.93,
            7.08,
            9.07,
            6.38,
            8.04,
            6.23,
            7.08,
            8.56,
            9.53,
            8.04,
            8.93,
            6.23,
            8.56,
            6.38,
            7.65,
        ],
    ]

    from PyBioMed.PyDNA.PyDNAutil import NormalizeIndex

    dac = GetDAC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Twist", "Tilt"])
    print(dac)
    print(len(dac))

    dac = GetDAC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(dac)
    print(len(dac))

    dac = GetDAC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Twist", "Tilt"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(dac)
    print(len(dac))
    print("\n")

    dcc = GetDCC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Twist", "Tilt"])
    print(dcc)
    print(len(dcc))

    dcc = GetDCC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(dcc)
    print(len(dcc))

    dcc = GetDCC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Twist", "Tilt"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(dcc)
    print(len(dcc))
    print("\n")

    print("DACC")
    dacc = GetDACC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Twist", "Tilt"]
    )
    print(dacc)
    print(len(dacc))

    dacc = GetDACC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(dacc)
    print(len(dacc))

    dac = GetDACC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Twist", "Tilt"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(dac)
    print(len(dac))
    print("\n")

    phyche_index = [
        [
            7.176,
            6.272,
            4.736,
            7.237,
            3.810,
            4.156,
            4.156,
            6.033,
            3.410,
            3.524,
            4.445,
            6.033,
            1.613,
            5.087,
            2.169,
            7.237,
            3.581,
            3.239,
            1.668,
            2.169,
            6.813,
            3.868,
            5.440,
            4.445,
            3.810,
            4.678,
            5.440,
            4.156,
            2.673,
            3.353,
            1.668,
            4.736,
            4.214,
            3.925,
            3.353,
            5.087,
            2.842,
            2.448,
            4.678,
            3.524,
            3.581,
            2.448,
            3.868,
            4.156,
            3.467,
            3.925,
            3.239,
            6.272,
            2.955,
            3.467,
            2.673,
            1.613,
            1.447,
            3.581,
            3.810,
            3.410,
            1.447,
            2.842,
            6.813,
            3.810,
            2.955,
            4.214,
            3.581,
            7.176,
        ]
    ]

    print("Begin TAC")
    tac = GetTAC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Dnase I", "Nucleosome"]
    )
    print(tac)
    print(len(tac))

    tac = GetTAC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(tac)
    print(len(tac))

    tac = GetTAC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Dnase I", "Nucleosome"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(tac)
    print(len(tac))
    print("\n")

    print("Begin TCC")
    tcc = GetTCC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Dnase I", "Nucleosome"]
    )
    print(tcc)
    print(len(tcc))

    tcc = GetTCC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(tcc)
    print(len(tcc))

    tcc = GetTCC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Dnase I", "Nucleosome"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(tcc)
    print(len(tcc))
    print("\n")

    print("Begin TACC")
    tacc = GetTACC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", phyche_index=["Dnase I", "Nucleosome"]
    )
    print(tacc)
    print(len(tacc))

    tacc = GetTACC("GACTGAACTGCACTTTGGTTTCATATTATTTGCTC", all_property=True)
    print(tacc)
    print(len(tacc))

    tacc = GetTACC(
        "GACTGAACTGCACTTTGGTTTCATATTATTTGCTC",
        phyche_index=["Dnase I", "Nucleosome"],
        extra_phyche_index=NormalizeIndex(phyche_index, is_convert_dict=True),
    )
    print(tacc)
    print(len(tacc))
    print("\n")
